import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'
import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment.js';

let camera, mesh
let scene
let renderer
let w = window.innerWidth, h = window.innerHeight
let x = 2500, y = 600, z = 2000
let LEN = 2000
function main() {
  createRenderer()
  creatCamera()
  createGrid()
  createLight()
  creatGeometry()
}

function creatCamera() {
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera(45, w / h, 1, 10000)
  camera.position.set(x, y, z)
  camera.up.y = 1
  camera.lookAt(scene.position)
}
function createRenderer() {
  renderer = new THREE.WebGLRenderer({ antialias: true })

  renderer.setSize(w, h)
  // renderer.setClearColor(0xe8e5e2)
  document.body.appendChild(renderer.domElement)

}
let positions = []
let wheels = []
let obj
let buffer = new THREE.BufferGeometry()
function creatGeometry() {
  let manger = new THREE.LoadingManager()
  new OBJLoader(manger).load(
    '/static/male.obj', (obj) => {
      obj.traverse((child) => {
        if (child.isMesh) {
          positions.push(...child.geometry.attributes.position.array)
        }
      })
      buffer.setAttribute('position', new THREE.BufferAttribute(new Float32Array(positions), 3))
      let material = new THREE.PointsMaterial({
        size: 3,
        color: 0x38dde0,
      });
      mesh = new THREE.Points(buffer, material)
      scene.add(mesh)
    }
  )
  let dracoLoader = new DRACOLoader();
  dracoLoader.setDecoderPath('/static/draco/gltf/');

  let bodyMaterial = new THREE.MeshPhysicalMaterial({
    color: 0x8020ac, metalness: 0.6, roughness: 0.4, clearcoat: 0.05, clearcoatRoughness: 0.05
  });

  let detailsMaterial = new THREE.MeshStandardMaterial({
    color: 0x2b75ce, metalness: 1.0, roughness: 0.5
  });

  let glassMaterial = new THREE.MeshPhysicalMaterial({
    color: 0x288486, metalness: 0, roughness: 0.1, transmission: 0.9, transparent: true
  });
  let shadow = new THREE.TextureLoader().load('/static/ferrari_ao.png')
  new GLTFLoader(manger).setDRACOLoader(dracoLoader).load(
    '/static/ferrari.glb',
    (gltf) => {
      console.log('====', gltf);
      let carModel = gltf.scene.children[0]
      carModel.getObjectByName('body').material = bodyMaterial;

      carModel.getObjectByName('rim_fl').material = detailsMaterial;
      carModel.getObjectByName('rim_fr').material = detailsMaterial;
      carModel.getObjectByName('rim_rr').material = detailsMaterial;
      carModel.getObjectByName('rim_rl').material = detailsMaterial;
      carModel.getObjectByName('trim').material = detailsMaterial;

      carModel.getObjectByName('glass').material = glassMaterial;

      wheels.push(
        carModel.getObjectByName('wheel_fl'),
        carModel.getObjectByName('wheel_fr'),
        carModel.getObjectByName('wheel_rl'),
        carModel.getObjectByName('wheel_rr')
      );

      // shadow
      const mesh = new THREE.Mesh(
        new THREE.PlaneGeometry(0.655 * 4, 1.3 * 4),
        new THREE.MeshBasicMaterial({
          map: shadow, side: THREE.DoubleSide, blending: THREE.MultiplyBlending, toneMapped: false, transparent: true
        })
      );
      mesh.rotateX(-Math.PI / 2)
      // mesh.position.y -=0.1
      carModel.add(mesh)
      // car.scale = new THREE.Vector3(100,100,100)
      carModel.scale.set(120, 120, 120)
      carModel.position.set(0, 0, 2000)
      obj = carModel
      scene.add(carModel)
    }
  )

}
function run() {
  if (!mesh) return
  const positions = mesh.geometry.attributes.position
  const initialPositions = mesh.geometry.attributes.position;

  let array = positions?.array || []
  for (let i = 0; i < array.length; i++) {
    const px = positions.getX(i);
    const py = positions.getY(i);
    const pz = positions.getZ(i);
    const ix = initialPositions.getX(i);
    const iy = initialPositions.getY(i);
    const iz = initialPositions.getZ(i);
    const dx = Math.abs(px - ix);
    const dy = Math.abs(py - iy);
    const dz = Math.abs(pz - iz);
    if (py > 0) {
      positions.setXYZ(
        i,
        px + 1.5 * (0.50 - Math.random()) * 1,
        py + 3.0 * (0.25 - Math.random()) * 2,
        pz + 1.5 * (0.50 - Math.random()) * 1
      );
    } else {
      positions.setXYZ(
        i,
        px + 1.5 * (0.50 - Math.random()) * 2,
        py + 3.0 * (0.25 + Math.random()) * 2,
        pz + 1.5 * (0.50 - Math.random()) * 2
      );
    }

  }
  positions.needsUpdate = true
}
function createGrid() {
  let grid = new THREE.GridHelper(9000, 50)
  scene.add(grid)
}

function createLight() {
  var light = new THREE.DirectionalLight(0xeeeeee, 1, 1200, 1)
  light.position.set(0, 1000, 2)
  scene.add(light)

  var light2 = new THREE.AmbientLight(0xffffff, 1, 1200, 1)
  light2.position.set(0, 1000, 2)
  scene.add(light2)
}
let theta = 0
function render() {
  if (obj) {
    if (obj.position.x > -800) {
      for (let i = 0; i < wheels.length; i++) {
        const wheel = wheels[i];
        wheel.rotateX(-0.13)
      }
    }
    theta += 0.8
    if (theta < 90) {
      obj.rotateY(Math.sin(THREE.Math.degToRad(0.8)))
      obj.position.x = 1500 * Math.sin(THREE.Math.degToRad(theta))
      obj.position.z = 1500 * Math.cos(THREE.Math.degToRad(theta))
    } else {
      obj.rotateY(0)
      if (x > 1500) {
        camera.position.set(x -= 10, y, z -= 8)
      }
      if(obj.position.x < 0){
        run()
      }
      if(obj.position.x > -800){
        obj.position.x -= 8
      }
    }
  }

  renderer.render(scene, camera)
  requestAnimationFrame(render)
}

main()
render()

// /** --------------------鼠标控件对象--------------------- */
let controls = new OrbitControls(camera, renderer.domElement); //创建控件对象
controls.addEventListener("change", render); //监听鼠标、键盘事件


